package com.sneakxy.mybase4j.base.fastdfs;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerServer;
import org.csource.fastdfs.UploadStream;

public class StorageClient2 extends StorageClient1 {

	public StorageClient2() {
		super();
	}

	public StorageClient2(TrackerServer trackerServer, StorageServer storageServer) {
		super(trackerServer, storageServer);
	}

	public int modify_file(String group_name, String appender_filename, InputStream is, long file_offset,
			long file_size) throws IOException, MyException {
		try {
			return this.do_modify_file(group_name, appender_filename, file_offset, file_size,
					new UploadStream(is, file_size));
		} finally {
			is.close();
		}
	}

	public String[] upload_file(InputStream is, long file_size, String file_ext_name, NameValuePair[] meta_list)
			throws IOException, MyException {
		final String group_name = null;
		return this.upload_file(group_name, is, file_size, file_ext_name, meta_list);
	}

	protected String[] upload_file(String group_name, InputStream is, long file_size, String file_ext_name,
			NameValuePair[] meta_list) throws IOException, MyException {
		final byte cmd = ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_FILE;
		return this.upload_file(cmd, group_name, is, file_size, file_ext_name, meta_list);
	}

	protected String[] upload_file(byte cmd, String group_name, InputStream is, long file_size, String file_ext_name,
			NameValuePair[] meta_list) throws IOException, MyException {
		try {
			return this.do_upload_file(cmd, group_name, null, null, file_ext_name, file_size,
					new UploadStream(is, file_size), meta_list);
		} finally {
			is.close();
		}
	}

	public String[] upload_file(String group_name, String master_filename, String prefix_name, InputStream is,
			long file_size, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException {
		if ((group_name == null || group_name.length() == 0)
				|| (master_filename == null || master_filename.length() == 0) || (prefix_name == null)
				|| file_ext_name == null) {
			throw new MyException("invalid arguement");
		}
		try {
			return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, group_name, master_filename,
					prefix_name, file_ext_name, file_size, new UploadStream(is, file_size), meta_list);
		} finally {
			is.close();
		}
	}

	public String[] upload_appender_file(InputStream is, long file_size, String file_ext_name,
			NameValuePair[] meta_list) throws IOException, MyException {
		final String group_name = null;
		return this.upload_appender_file(group_name, is, file_size, file_ext_name, meta_list);
	}

	protected String[] upload_appender_file(String group_name, InputStream is, long file_size, String file_ext_name,
			NameValuePair[] meta_list) throws IOException, MyException {
		final byte cmd = ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE;
		return this.upload_file(cmd, group_name, is, file_size, file_ext_name, meta_list);
	}

	public int append_file(String group_name, String appender_filename, InputStream is, long file_size)
			throws IOException, MyException {
		try {
			return this.do_append_file(group_name, appender_filename, file_size, new UploadStream(is, file_size));
		} finally {
			is.close();
		}
	}

	public String upload_file2(InputStream is, long file_size, String file_ext_name, NameValuePair[] meta_list)
			throws IOException, MyException {
		String parts[] = this.upload_file(is, file_size, file_ext_name, meta_list);
		if (parts != null) {
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
		} else {
			return null;
		}
	}

	public String upload_file2(String group_name, InputStream is, long file_size, String file_ext_name,
			NameValuePair[] meta_list) throws IOException, MyException {
		String parts[] = this.upload_file(group_name, is, file_size, file_ext_name, meta_list);
		if (parts != null) {
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
		} else {
			return null;
		}
	}

	public int download_file(String group_name, String remote_filename, OutputStream out) throws IOException, MyException {
		final long file_offset = 0;
		final long download_bytes = 0;
		return this.download_file(group_name, remote_filename, file_offset, download_bytes, out);
	}

	public int download_file(String group_name, String remote_filename, long file_offset, long download_bytes,
			OutputStream out) throws IOException, MyException {
		boolean bNewConnection = this.newReadableStorageConnection(group_name, remote_filename);
		Socket storageSocket = this.storageServer.getSocket();
		try {
			ProtoCommon.RecvHeaderInfo header;
			try {
				this.errno = 0;
				this.send_download_package(group_name, remote_filename, file_offset, download_bytes);
				InputStream in = storageSocket.getInputStream();
				header = ProtoCommon.recvHeader(in, ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
				this.errno = header.errno;
				if (header.errno != 0) {
					return header.errno;
				}

				byte[] buff = new byte[256 * 1024];
				long remainBytes = header.body_len;
				int bytes;

				// System.out.println("expect_body_len=" + header.body_len);

				while (remainBytes > 0) {
					if ((bytes = in.read(buff, 0, remainBytes > buff.length ? buff.length : (int) remainBytes)) < 0) {
						throw new IOException(
								"recv package size " + (header.body_len - remainBytes) + " != " + header.body_len);
					}

					out.write(buff, 0, bytes);
					remainBytes -= bytes;
				}
				return 0;
			} catch (IOException ex) {
				if (this.errno == 0) {
					this.errno = ProtoCommon.ERR_NO_EIO;
				}

				throw ex;
			} finally {
				out.close();
			}
		} catch (IOException ex) {
			if (!bNewConnection) {
				try {
					this.storageServer.close();
				} catch (IOException ex1) {
					ex1.printStackTrace();
				} finally {
					this.storageServer = null;
				}
			}

			throw ex;
		} finally {
			if (bNewConnection) {
				try {
					this.storageServer.close();
				} catch (IOException ex1) {
					ex1.printStackTrace();
				} finally {
					this.storageServer = null;
				}
			}
		}
	}
	
	public int download_file2(String file_id, OutputStream out) throws IOException, MyException {
		final long file_offset = 0;
		final long download_bytes = 0;
		return this.download_file2(file_id, file_offset, download_bytes, out);
	}
	
	public int download_file2(String file_id, long file_offset, long download_bytes, OutputStream out) throws IOException, MyException {
		String[] parts = new String[2];
		this.errno = split_file_id(file_id, parts);
		if (this.errno != 0) {
			return this.errno;
		}
		return this.download_file(parts[0], parts[1], file_offset, download_bytes, out);
	}
	
}
